/**
 * Copyright (C) 2023 maminjie <canpool@163.com>
 * Copyright (C) 2022 Syarif Fakhri
 * Copyright (C) 2017 Uwe Kindler
 * SPDX-License-Identifier: LGPL-2.1
 **/

#include "QxDockAutoHideTab.h"
#include "QxDockAutoHideContainer.h"
#include "QxDockAutoHideSideBar.h"
#include "QxDockAreaWidget.h"
#include "QxDockManager.h"
#include "QxDockWidget.h"

#include <QApplication>
#include <QBoxLayout>
#include <QElapsedTimer>

QX_BEGIN_NAMESPACE

/**
 * Private data class of DockWidgetTab class (pimpl)
 */
struct DockAutoHideTabPrivate {
    DockAutoHideTab *_this;
    DockWidget *dockWidget = nullptr;
    DockAutoHideSideBar *SideBar = nullptr;
    Qt::Orientation Orientation{Qt::Vertical};
    QElapsedTimer TimeSinceHoverMousePress;

    /**
     * Private data constructor
     */
    DockAutoHideTabPrivate(DockAutoHideTab *_public);

    /**
     * Update the orientation, visibility and spacing based on the area of
     * the side bar
     */
    void updateOrientation();

    /**
     * Convenience function to ease dock container access
     */
    DockContainerWidget *dockContainer() const
    {
        return dockWidget ? dockWidget->dockContainer() : nullptr;
    }

    /**
     * Forward this event to the dock container
     */
    void forwardEventToDockContainer(QEvent *event)
    {
        auto DockContainer = dockContainer();
        if (DockContainer) {
            DockContainer->handleAutoHideWidgetEvent(event, _this);
        }
    }
};   // struct DockWidgetTabPrivate

DockAutoHideTabPrivate::DockAutoHideTabPrivate(DockAutoHideTab *_public) : _this(_public)
{
}

void DockAutoHideTabPrivate::updateOrientation()
{
    bool IconOnly = DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly);
    if (IconOnly && !_this->icon().isNull()) {
        _this->setText("");
        _this->setOrientation(Qt::Horizontal);
    } else {
        auto area = SideBar->sideBarLocation();
        _this->setOrientation((area == SideBarBottom || area == SideBarTop) ? Qt::Horizontal : Qt::Vertical);
    }
}

void DockAutoHideTab::setSideBar(DockAutoHideSideBar *SideTabBar)
{
    d->SideBar = SideTabBar;
    if (d->SideBar) {
        d->updateOrientation();
    }
}

DockAutoHideSideBar *DockAutoHideTab::sideBar() const
{
    return d->SideBar;
}

void DockAutoHideTab::removeFromSideBar()
{
    if (d->SideBar == nullptr) {
        return;
    }
    d->SideBar->removeTab(this);
    setSideBar(nullptr);
}

DockAutoHideTab::DockAutoHideTab(QWidget *parent) : DockPushButton(parent), d(new DockAutoHideTabPrivate(this))
{
    setAttribute(Qt::WA_NoMousePropagation);
    setFocusPolicy(Qt::NoFocus);
}

DockAutoHideTab::~DockAutoHideTab()
{
    QX_DOCK_PRINT("~CDockWidgetSideTab()");
    delete d;
}

void DockAutoHideTab::updateStyle()
{
    internal::repolishStyle(this, internal::RepolishDirectChildren);
    update();
}

SideBarLocation DockAutoHideTab::sideBarLocation() const
{
    if (d->SideBar) {
        return d->SideBar->sideBarLocation();
    }

    return SideBarLeft;
}

void DockAutoHideTab::setOrientation(Qt::Orientation Orientation)
{
    d->Orientation = Orientation;
    if (orientation() == Qt::Horizontal) {
        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
    } else {
        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
    }
    DockPushButton::setButtonOrientation((Qt::Horizontal == Orientation) ? DockPushButton::Horizontal
                                                                      : DockPushButton::VerticalTopToBottom);
    updateStyle();
}

Qt::Orientation DockAutoHideTab::orientation() const
{
    return d->Orientation;
}

bool DockAutoHideTab::isActiveTab() const
{
    if (d->dockWidget && d->dockWidget->autoHideDockContainer()) {
        return d->dockWidget->autoHideDockContainer()->isVisible();
    }

    return false;
}

DockWidget *DockAutoHideTab::dockWidget() const
{
    return d->dockWidget;
}

void DockAutoHideTab::setDockWidget(DockWidget *dockWidget)
{
    if (!dockWidget) {
        return;
    }
    d->dockWidget = dockWidget;
    setText(dockWidget->windowTitle());
    setIcon(d->dockWidget->icon());
    setToolTip(dockWidget->windowTitle());
}

bool DockAutoHideTab::event(QEvent *event)
{
    if (!DockManager::testAutoHideConfigFlag(DockManager::AutoHideShowOnMouseOver)) {
        return Super::event(event);
    }

    switch (event->type()) {
    case QEvent::Enter:
    case QEvent::Leave:
        d->forwardEventToDockContainer(event);
        break;

    case QEvent::MouseButtonPress:
        // If AutoHideShowOnMouseOver is active, then the showing is triggered
        // by a MousePressEvent sent to this tab. To prevent accidental hiding
        // of the tab by a mouse click, we wait at least 500 ms before we accept
        // the mouse click
        if (!event->spontaneous()) {
            d->TimeSinceHoverMousePress.restart();
            d->forwardEventToDockContainer(event);
        } else if (d->TimeSinceHoverMousePress.hasExpired(500)) {
            d->forwardEventToDockContainer(event);
        }
        break;

    default:
        break;
    }
    return Super::event(event);
}

bool DockAutoHideTab::iconOnly() const
{
    return DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly) && !icon().isNull();
}

QX_END_NAMESPACE
